package threads;

import java.awt.EventQueue;
import java.io.File;
import java.io.IOException;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Queue;

import main.GameDialog;

import org.jdom.Document;
import org.jdom.Element;
import org.jdom.JDOMException;
import org.jdom.input.SAXBuilder;

public class SaveFolderSearcher extends Thread {

	private final GameDialog context;
	private final String game;
	
	private HashMap<String,Integer> startList;
	private HashMap<String,Integer> priorityList;
	private String[] saveFolder;
	
	private String lastGameFolder;
	private boolean isKilled;

	@SuppressWarnings("unchecked")
	public SaveFolderSearcher(GameDialog context, String game) throws JDOMException, IOException{
		this.context = context;
		this.game = game;
		lastGameFolder = null;
		
		isKilled = false;
		
		String path = getClass().getResource("/config.txt").getPath();
		File xml = new File(path);
		
		SAXBuilder builder = new SAXBuilder();
		Document  doc = builder.build(xml);
		Element root = doc.getRootElement();
		
		Iterator<Element> it;
		
		//generate start-list
		startList = new HashMap<String, Integer>();
		List<Element> start = root.getChildren("startfolder");
		it = start.iterator();
		while(it.hasNext()){
			Element next =  it.next();
			String folder = findVariables(next.getTextNormalize());
			if(folder!=null)
				if(next.getAttribute("searchdepth")!=null){
					startList.put(folder, next.getAttribute("searchdepth").getIntValue());
				}else{
					startList.put(folder, 2);
				}
		}
		
		//generate priority-list
		priorityList = new HashMap<String, Integer>();
		List<Element> priority = root.getChildren("priorityfolder");
		it = priority.iterator();
		while(it.hasNext()){
			Element next = it.next();
			String folder = findVariables(next.getTextNormalize());
			if(folder!=null)
				if(next.getAttribute("searchdepth")!=null){
					priorityList.put(folder, next.getAttribute("searchdepth").getIntValue());
				}else{
					priorityList.put(folder, 2);
				}
		}
		
		//generate savefolder-list
		List<Element> save = root.getChildren("savefolder");
		saveFolder = new String[save.size()];
		Object[] ele = save.toArray();
		for(int i=0; i<ele.length; i++) {
			Element e = (Element) ele[i];
			saveFolder[i] = e.getTextNormalize();  
		}
	}
	
	private String findVariables(String text) {
		String result = "";
		for(int i = 0; i<text.length(); i++){
			if(text.charAt(i)=='%'){
				int j = text.indexOf('%', i+1);
				if(j!=-1){
					String sub = text.substring(i+1, j);
					String env = System.getenv(sub);
					if(env!=null) {
						result += env;
						i = j;
					}
					else return null;
				} else return null;
			} else result += text.charAt(i);
		}
		return result;
	}

	@Override
	public void run() {
		Iterator<String> it1 = startList.keySet().iterator();
		while(it1.hasNext()){
			String folder = it1.next();
			File start = new File(folder);
			int p = startList.get(folder);
			
			Queue<File> q = new LinkedList<File>();
			q.offer(start);
			
			for(int i=0; i<=p; i++){
				File f;
				q.offer(null);
				while((f = q.poll())!=null){
					if(f.isDirectory()){
						final File aaa = f;
						//kill
						if(isKilled) return;
						EventQueue.invokeLater(new Runnable(){
							@Override
							public void run() {
								context.reportSaveFolderStatus("Checking",
										aaa.getAbsolutePath());
							}
						});
						final String res = checkPriority(f);
						if(res!=null) {
							//kill
							if(isKilled) return;
							EventQueue.invokeLater(new Runnable(){
								@Override
								public void run() {
									context.showFileChooser(res);
								}
							});
							return;
						}
						final String res2 = checkGameFolder(f);
						if(res2!=null) {
							EventQueue.invokeLater(new Runnable(){
								@Override
								public void run() {
									context.showFileChooser(res2);
								}
							});
							return;
						}
						File[] files = f.listFiles();
						if(files!=null)
							for(File a : f.listFiles()) if(a.isDirectory()) q.offer(a);
					}
				}
			}
		}
		//kill
		if(isKilled) return;
		final String aaa = lastGameFolder;
		EventQueue.invokeLater(new Runnable(){
			@Override
			public void run() {
				if(aaa!=null) context.showFileChooser(aaa);
				else context.showFileChooser(System.getProperty("user.home"));
			}
		});
	}

	private String checkGameFolder(final File f) {
		String name = getFolderName(f);
		if(name==null) return null;
		name = name.toLowerCase();

		String[] gameparts = game.split(" ");
		for(int i = 0; i<gameparts.length; i++){
			String part = gameparts[i].toLowerCase();
			if(!name.contains(part)) return null;
		}
		EventQueue.invokeLater(new Runnable(){
			@Override
			public void run() {
				context.reportSaveFolderStatus("Match",
						game+" with "+f.getAbsolutePath()+"--");
			}
		});
		lastGameFolder = f.getAbsolutePath();
		String res = findSaveFolder(f);
		return res;
	}

	private String findSaveFolder(File start) {	
		Queue<File> q = new LinkedList<File>();
		q.offer(start);
		
		while(q.size()>0){
			File f;
			q.offer(null);
			while((f = q.poll())!=null){
				if(f.isDirectory()){
					final File aaa = f;
					EventQueue.invokeLater(new Runnable(){
						@Override
						public void run() {
							context.reportSaveFolderStatus("SaveSeraching",
									aaa.getAbsolutePath());
						}
					});
					String folder = getFolderName(f);
					if(folder!=null){
						folder = folder.toLowerCase();
						for(int a = 0; a <saveFolder.length; a++){
							if(folder.contains(saveFolder[a].toLowerCase())) {
								return f.getAbsolutePath();
							}
						}
					}
					File[] files = f.listFiles();
					if(files!=null)
						for(File a : f.listFiles()) if(a.isDirectory()) q.offer(a);
				}
			}
		}
		return null;
	}

	private String checkPriority(File start) {
		String name = getFolderName(start);
		if(name==null) return null;
		name = name.toLowerCase();
		
		Iterator<String> it = priorityList.keySet().iterator();
		while(it.hasNext()){
			String next = it.next().toLowerCase();
			if(name.contains(next)){
				int p = priorityList.get(next);
				
				Queue<File> q = new LinkedList<File>();
				q.offer(start);
				
				for(int i=0; i<=p; i++){
					File f;
					q.offer(null);
					while((f = q.poll())!=null){
						if(f.isDirectory()){
							final File aaa = f;
							EventQueue.invokeLater(new Runnable(){
								@Override
								public void run() {
									context.reportSaveFolderStatus("Priority",
											aaa.getAbsolutePath());
								}
							});
							String res = checkGameFolder(f);
							if(res!=null) return res;
							File[] files = f.listFiles();
							if(files!=null)
								for(File a : f.listFiles()) if(a.isDirectory()) q.offer(a);
						}
					}
				}
			}
		}
		
		return null;
	}

	private String getFolderName(File f) {
		if(f==null) return null;
		String path = f.getAbsolutePath();
		int i = path.lastIndexOf(File.separator);
		if(i!=-1&&(i+1)<path.length()) return path.substring(i+1, path.length());
		return null;
	}

	public void kill() {
		this.isKilled = true;	
	}

}
